<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GPS Distance Calculator</title>
  <!-- 引入 Font Awesome CSS -->
  <link rel="stylesheet" href="static/css/all.min.css">
  <!-- 引入 Element UI CSS -->
  <link rel="stylesheet" href="static/element-ui/lib/theme-chalk/index.css">
  <style>
    /* 容器样式 */
    .gps-calculator-container {
      padding: 20px;
      background-color: #f9f9f9;
      border: 1px solid #dcdcdc;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      margin: 0 20px;
    }

    /* 标题样式 */
    .title {
      text-align: center;
      color: #333;
      font-size: 24px;
      margin-bottom: 20px;
      font-weight: bold;
      text-transform: uppercase;
    }

    /* 列容器样式 */
    .columns-container {
      display: flex;
      gap: 10px; /* 设置两栏之间的间距为10px */
    }

    /* 左栏样式 */
    .column {
      flex: 1;
      padding: 10px;
      background-color: #fff;
      border-radius: 4px;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
    }

    .left-column {
      border-right: 1px solid #dcdcdc;
    }

    .right-column {
      border-left: 1px solid #dcdcdc;
    }

    /* 表单样式 */
    .form-no-wrap .el-form-item__label {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .centered-button .el-row {
      margin: 0 auto;
    }

    .centered-result .el-row {
      margin: 0 auto;
      width: fit-content;
    }

    /* 自定义 el-alert 样式 */
    .custom-alert {
      padding: 12px 48px 12px 16px; /* 增加右边的内边距 */
      position: relative;
      display: flex;
      align-items: center; /* 垂直居中对齐 */
      justify-content: space-between; /* 内容和关闭按钮之间留出空间 */
    }

    .custom-alert .el-alert__content {
      flex: 1; /* 确保内容占据剩余空间 */
    }

    .custom-alert .el-alert__closebtn {
      position: absolute;
      top: 50%;
      right: 16px; /* 调整关闭按钮的位置 */
      transform: translateY(-50%); /* 垂直居中对齐 */
    }

    /* 自定义 Precision 按钮样式 */
    .precision-buttons .el-row {
      display: flex;
      justify-content: center; /* 水平居中 */
      align-items: center; /* 垂直居中 */
      gap: 10px; /* 按钮之间的间距 */
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="gps-calculator-container">
      <h2 class="title">GPS Distance Calculator</h2>
      <div class="columns-container">
        <div class="column left-column">
          <el-form label-width="auto" class="form-no-wrap">
            <el-form-item label="Latitude 1 (DMS)">
              <el-input v-model="lat1DMS" placeholder="e.g., 52 13 35" @change="convertDMS('lat1DMS', 'lat1Decimal')"></el-input>
            </el-form-item>
            <el-form-item label="Latitude 1 (Decimal)">
              <el-input v-model="lat1Decimal" disabled></el-input>
            </el-form-item>
            <el-form-item label="Longitude 1 (DMS)">
              <el-input v-model="lng1DMS" placeholder="e.g., 21 0 44" @change="convertDMS('lng1DMS', 'lng1Decimal')"></el-input>
            </el-form-item>
            <el-form-item label="Longitude 1 (Decimal)">
              <el-input v-model="lng1Decimal" disabled></el-input>
            </el-form-item>
            <el-form-item label="Latitude 2 (DMS)">
              <el-input v-model="lat2DMS" placeholder="e.g., 52 24 23" @change="convertDMS('lat2DMS', 'lat2Decimal')"></el-input>
            </el-form-item>
            <el-form-item label="Latitude 2 (Decimal)">
              <el-input v-model="lat2Decimal" disabled></el-input>
            </el-form-item>
            <el-form-item label="Longitude 2 (DMS)">
              <el-input v-model="lng2DMS" placeholder="e.g., 16 55 30" @change="convertDMS('lng2DMS', 'lng2Decimal')"></el-input>
            </el-form-item>
            <el-form-item label="Longitude 2 (Decimal)">
              <el-input v-model="lng2Decimal" disabled></el-input>
            </el-form-item>
            <el-form-item label="Precision" class="precision-buttons">
              <el-row :gutter="10">
                <el-col :span="11">
                  <el-form-item label="Minute Precision" label-width="auto">
                    <el-input-number v-model="minutesPrecision" :min="0" :max="10" placeholder="e.g., 2" @change="validateInt('minutesPrecision')"></el-input-number>
                  </el-form-item>
                </el-col>
                <el-col :span="11">
                  <el-form-item label="Second Precision" label-width="auto">
                    <el-input-number v-model="secondsPrecision" :min="0" :max="10" placeholder="e.g., 3" @change="validateInt('secondsPrecision')"></el-input-number>
                  </el-form-item>
                </el-col>
              </el-row>
            </el-form-item>
            <el-form-item class="centered-button">
              <el-row type="flex" justify="center">
                <el-button type="primary" @click="calculateDistance">Calculate Distance</el-button>
              </el-row>
            </el-form-item>
            <el-form-item v-if="distance !== null" class="centered-result">
              <el-row type="flex" justify="center">
                <el-alert :title="`Distance: ${distance.toFixed(2)} cm (${(distance / 100).toFixed(2)} m)`" type="info" show-icon closable @close="clearDistance" class="custom-alert"></el-alert>
              </el-row>
            </el-form-item>
          </el-form>
        </div>
        <div class="column right-column">
          <el-form label-width="auto" class="form-no-wrap">
            <el-form-item label="Latitude 1 (Decimal)">
              <el-input v-model="lat1DecimalDirect" placeholder="e.g., 52.2296756" @change="validateDecimal('lat1DecimalDirect')"></el-input>
            </el-form-item>
            <el-form-item label="Longitude 1 (Decimal)">
              <el-input v-model="lng1DecimalDirect" placeholder="e.g., 21.0122287" @change="validateDecimal('lng1DecimalDirect')"></el-input>
            </el-form-item>
            <el-form-item label="Latitude 2 (Decimal)">
              <el-input v-model="lat2DecimalDirect" placeholder="e.g., 52.406374" @change="validateDecimal('lat2DecimalDirect')"></el-input>
            </el-form-item>
            <el-form-item label="Longitude 2 (Decimal)">
              <el-input v-model="lng2DecimalDirect" placeholder="e.g., 16.9251681" @change="validateDecimal('lng2DecimalDirect')"></el-input>
            </el-form-item>
            <el-form-item class="centered-button">
              <el-row type="flex" justify="center">
                <el-button type="primary" @click="calculateDistanceDirect">Calculate Distance</el-button>
              </el-row>
            </el-form-item>
            <el-form-item v-if="distanceDirect !== null" class="centered-result">
              <el-row type="flex" justify="center">
                <el-alert :title="`Distance: ${distanceDirect.toFixed(2)} cm (${(distanceDirect / 100).toFixed(2)} m)`" type="info" show-icon closable @close="clearDistanceDirect" class="custom-alert"></el-alert>
              </el-row>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </div>
  </div>

  <!-- 引入 Vue.js -->
  <script src="static/vue/vue.min.js"></script>
  <!-- 引入 Element UI JS -->
  <script src="static/element-ui/lib/index.js"></script>
  <script>
    new Vue({
      el: '#app',
      data() {
        return {
          lat1DMS: '',
          lng1DMS: '',
          lat2DMS: '',
          lng2DMS: '',
          lat1Decimal: '',
          lng1Decimal: '',
          lat2Decimal: '',
          lng2Decimal: '',
          lat1DecimalDirect: '',
          lng1DecimalDirect: '',
          lat2DecimalDirect: '',
          lng2DecimalDirect: '',
          distance: null,
          distanceDirect: null,
          secondsPrecision: 3, // 秒的默认精度为3
          minutesPrecision: 2, // 分的默认精度为2
        };
      },
      methods: {
        // 验证DMS格式
        validateDMS(key) {
          const regex = new RegExp(`^\\d{1,3} \\d{1,2}(\\.\\d{1,${this.minutesPrecision}})? \\d{1,2}(\\.\\d{1,${this.secondsPrecision}})?$`);
          if (!regex.test(this[key])) {
            this.$message.error(`${key} must be in DMS format with precision up to ${this.minutesPrecision} decimal places for minutes and ${this.secondsPrecision} decimal places for seconds (e.g., 52 13.12 35.123)`);
            this[key] = '';
          }
        },
        // 验证十进制度格式
        validateDecimal(key) {
          const regex = /^-?\d+(\.\d+)?$/;
          if (!regex.test(this[key])) {
            this.$message.error(`${key} must be a valid decimal number (e.g., 52.2296756)`);
            this[key] = '';
          }
        },
        // 验证整数
        validateInt(key) {
          const value = this[key];
          if (!Number.isInteger(value)) {
            this.$message.error(`${key} must be an integer`);
            this[key] = Math.floor(value);
          }
        },
        // DMS转十进制度
        dmsToDecimal(dms) {
          const parts = dms.split(' ').map(Number);
          if (parts.length === 3) {
            const [d, m, s] = parts;
            return d + (m / 60) + (s / 3600);
          }
          return 0;
        },
        // 十进制度转DMS
        decimalToDMS(decimal) {
          const d = Math.floor(decimal);
          const m = ((decimal - d) * 60).toFixed(this.minutesPrecision);
          const s = (((decimal - d) * 60 - m) * 60).toFixed(this.secondsPrecision);
          return `${d} ${m} ${s}`;
        },
        // 转换DMS到十进制度并显示
        convertDMS(dmsKey, decimalKey) {
          this.validateDMS(dmsKey);
          this[decimalKey] = this.dmsToDecimal(this[dmsKey]).toFixed(7); // 固定保留7位小数
        },
        // 计算两点间的距离（基于DMS）
        calculateDistance() {
          const R = 6371000; // 地球半径，单位为米
          const lat1 = parseFloat(this.lat1Decimal);
          const lng1 = parseFloat(this.lng1Decimal);
          const lat2 = parseFloat(this.lat2Decimal);
          const lng2 = parseFloat(this.lng2Decimal);

          const φ1 = lat1 * Math.PI / 180; // φ, λ in radians
          const φ2 = lat2 * Math.PI / 180;
          const Δφ = (lat2 - lat1) * Math.PI / 180;
          const Δλ = (lng2 - lng1) * Math.PI / 180;

          const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
              Math.cos(φ1) * Math.cos(φ2) *
              Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
          const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

          this.distance = R * c * 100; // 距离转换为厘米
        },
        // 计算两点间的距离（基于十进制度）
        calculateDistanceDirect() {
          const R = 6371000; // 地球半径，单位为米
          const lat1 = parseFloat(this.lat1DecimalDirect);
          const lng1 = parseFloat(this.lng1DecimalDirect);
          const lat2 = parseFloat(this.lat2DecimalDirect);
          const lng2 = parseFloat(this.lng2DecimalDirect);

          const φ1 = lat1 * Math.PI / 180; // φ, λ in radians
          const φ2 = lat2 * Math.PI / 180;
          const Δφ = (lat2 - lat1) * Math.PI / 180;
          const Δλ = (lng2 - lng1) * Math.PI / 180;

          const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
              Math.cos(φ1) * Math.cos(φ2) *
              Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
          const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

          this.distanceDirect = R * c * 100; // 距离转换为厘米
        },
        // 清除DMS计算结果
        clearDistance() {
          this.distance = null;
        },
        // 清除十进制度计算结果
        clearDistanceDirect() {
          this.distanceDirect = null;
        }
      }
    });
  </script>
</body>
</html>